home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK1.toast / Development Kits (Disc 1) / QuickTime / Programming Stuff / Sample Code / Music Architecture / Mixed Bag / •QTMusic Sample Sequencer / Event Priority Queue.c next >
Encoding:
C/C++ Source or Header  |  1994-09-16  |  4.3 KB  |  276 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        Event Priority Queue.c
  3.  
  4.     Contains:    Event-ordering routines
  5.  
  6.     Written by:    dvb, based on classic algorithms. read the book, see the movie.
  7.  
  8.     Copyright:    © 1992-1994 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <10>     24-8-94    dvb        Fix write to nil.
  13.          <9>      9-8-94    dvb        zero out new queues, use longs only
  14.          <8>      6/4/94    PH        return an error
  15.          <7>     7/13/93    dvb        Test... again.
  16.          <6>     7/13/93    dvb        
  17.          <5>     7/13/93    dvb        -d
  18.          <4>     7/13/93    dvb        -d < Death By Seven:System Folder:OldComment
  19.         <2+>     5/19/93    dvb        New calls for sorting.
  20.          <2>     9/17/92    dvb        Flush call
  21.          <1>     5/10/92    dvb        first checked in
  22.          <0+>     5/10/92    dvb        first checked in
  23.  
  24. */
  25.  
  26.  
  27. /*
  28.  * file: Event Priority Queue.c
  29.  *
  30.  * This is an "ascending" priority queue,
  31.  * only the smallest event will be extracted.
  32.  *
  33.  * Started 6 May 1992, David Van Brink
  34.  */
  35.  
  36.  
  37.  
  38. /*
  39.  * Quick C. S. refresher...
  40.  *
  41.  * This is implemented as a balanced tree
  42.  * with the Property that every node is
  43.  * marked with an earlier time than its
  44.  * descendants. The tree is stored as
  45.  * an array, with the relationships of
  46.  * Parent and Child as #defined below.
  47.  *
  48.  * To insert a new event, we add it at
  49.  * the end of the array (the bottom of
  50.  * the tree) and bubble it up as needed
  51.  * to maintain the Property. Time: lg2(n).
  52.  *
  53.  * To extract the next event, we take
  54.  * the root of the tree (event[0]) and
  55.  * then bubble around the innards as
  56.  * needed. Time: lg2(n).
  57.  *
  58.  * I figure we can juggle a few hundred or
  59.  * thousand events this way with reasonable performance.
  60.  */
  61.  
  62.  
  63.  
  64. /*--------------------------
  65.     Inclusions
  66. --------------------------*/
  67.  
  68. #include <Memory.h>
  69.  
  70. #include "Event Priority Queue.h"
  71.  
  72. /*--------------------------
  73.     Local Prototypes
  74. --------------------------*/
  75.  
  76. #define LeftChild(x) ((x)+(x)+1)
  77. #define RightChild(x) (LeftChild(x)+1)
  78. #define Parent(x) (((x) - 1)>>1)
  79.  
  80.  
  81. /*--------------------------
  82.     Them Routines
  83. --------------------------*/
  84.  
  85.  
  86. EPQ *NewEPQ(long maxSize)
  87.     {
  88.     EPQ *q;
  89.  
  90.     q = (void *)NewPtrClear(sizeof(EPQ) + maxSize * sizeof(EPQEvent));
  91.     if(q)
  92.         {
  93.         q->size = 0;
  94.         q->maxSize = maxSize;
  95.         }
  96.  
  97.     return q;
  98.     }
  99.  
  100. short DisposeEPQ(EPQ *q)
  101.     {
  102.     if(q)
  103.         DisposePtr((void *)q);
  104.     return noErr;
  105.     }
  106.  
  107.  
  108. short AddEventEPQ(EPQ *q, const EPQEvent *inEvent)
  109. /*
  110.  * This routine must be indivisible, since Events
  111.  * will be extracted at interrupt level.
  112.  *
  113.  * This routine could be nicely optimized.
  114.  */
  115.     {
  116.     long index, parent;
  117.     EPQEvent e;
  118.     register long time;
  119.     register EPQEvent *pptr,*iptr;
  120.  
  121.     if(q->size == q->maxSize)
  122.         return -1;                    /* error */
  123.  
  124.     time = inEvent->time;
  125.     index = q->size;
  126.  
  127.     if(index)
  128.         {
  129.         iptr = &q->e[index];
  130.         goto x;
  131.         }
  132. loop:
  133.     if(index != 0)
  134.         {
  135.     x:
  136.         parent = Parent(index);
  137.         pptr = &q->e[parent];
  138.         if(time < pptr->time)
  139.             {
  140.             q->e[index] = *pptr;
  141.             index = parent;
  142.             iptr = pptr;
  143.             goto loop;
  144.             }
  145.         }
  146.  
  147.     q->e[index] = *inEvent;
  148.     ++ q->size;
  149.  
  150.     return 0;
  151.     }
  152.  
  153. long PeekTopEPQ(EPQ *q)
  154.     {
  155.     if(q->size)
  156.         return q->e[0].time;
  157.     else
  158.         return kEPQEmpty;
  159.     }
  160.  
  161. long GetSizeEPQ(EPQ *q)
  162.     {
  163.     return q->size;
  164.     }
  165.  
  166.  
  167.  
  168. void ExtractEventEPQ(EPQ *q, EPQEvent *outEvent)
  169.     {
  170.     register long index,left,right;
  171.     register long size;
  172.     register long temp;
  173.     register EPQEvent *i,*l,*r;
  174. //    EPQEvent tempE;
  175.  
  176.     *outEvent = q->e[0];
  177.  
  178.     size = --q->size;
  179.  
  180.     if(!size)
  181.         goto done;
  182.  
  183.     q->e[0] = q->e[size];
  184.  
  185.     index = 0;
  186.     i = &q->e[0];
  187.  
  188.     while(index < size)
  189.         {
  190.         left = LeftChild(index);
  191.  
  192.         /*
  193.          * step 1: put the smaller of left or right into L ptrs
  194.          */
  195.         if(left >= size)
  196.             goto done;
  197.  
  198.         right = left + 1;
  199.         l = &q->e[left];
  200.         r = l+1;
  201.  
  202.         if( (right <= size)
  203.                 && (r->time < l->time) )
  204.             {
  205.             left = right;
  206.             l = r;
  207.             }
  208.  
  209.         /*
  210.          * step 2: is i smaller than either of them? if so, done.
  211.          */
  212.         if(i->time < l->time)
  213.             goto done;
  214.  
  215.         #define swapit(a) \
  216.             temp = i->a; \
  217.             i->a = l->a; \
  218.             l->a = temp
  219.  
  220.         swapit(time);
  221.         swapit(data1);
  222.         swapit(data2);
  223.         swapit(data3);
  224.  
  225.         i = l;
  226.         index = left;
  227.         }
  228.  
  229. done:;
  230.     }
  231.  
  232.  
  233.  
  234. void FlushEPQ(EPQ *q)
  235.     {
  236.     if(q)
  237.         q->size = 0;
  238.     }
  239.  
  240.  
  241. void SortEPQ(EPQ *q)
  242. /*
  243.  * Sort the elements and
  244.  * put in the top of the
  245.  * event array.
  246.  */
  247.     {
  248.     EPQEvent e;
  249.     EPQEvent *w;
  250.  
  251.     w = &q->e[q->maxSize];
  252.  
  253.     while(q->size)
  254.         {
  255.         ExtractEventEPQ(q,&e);
  256.         --w;
  257.         *w = e;
  258.         }
  259.     }
  260.  
  261. EPQEvent *PeekIndexedEPQ(EPQ *q,long index)
  262. /*
  263.  * Positive index 0-max, or
  264.  * negative index to look at elements
  265.  * after sorting.
  266.  */
  267.     {
  268.     if(index >= 0)
  269.         return &q->e[index];
  270.     else
  271.         return &q->e[q->maxSize + index];
  272.     }
  273.  
  274.  
  275.  
  276.